import { Request, Response, NextFunction } from 'express';
import { validationResult } from 'express-validator';
import { ApiResponse, HttpStatus } from '../types/api';

/**
 * 验证错误处理中间件
 * 检查express-validator的验证结果，如果有错误则返回400状态码
 * @param req Express请求对象
 * @param res Express响应对象
 * @param next Express下一个中间件函数
 */
export const handleValidationErrors = (
  req: Request,
  res: Response,
  next: NextFunction
): void => {
  const errors = validationResult(req);
  
  if (!errors.isEmpty()) {
    const errorMessages = errors.array().map((error: any) => ({
      field: error.type === 'field' ? (error as any).path : 'unknown',
      message: error.msg,
      value: error.type === 'field' ? (error as any).value : undefined
    }));
    
    const response: ApiResponse<null> = {
      success: false,
      message: '数据验证失败',
      data: null,
      errors: errorMessages,
      timestamp: new Date().toISOString()
    };
    
    res.status(HttpStatus.BAD_REQUEST).json(response);
    return;
  }
  
  next();
};

/**
 * UUID参数验证中间件
 * 验证路径参数中的ID是否为有效的UUID格式
 * @param paramName 要验证的参数名称（默认为'id'）
 */
export const validateUUIDParam = (paramName: string = 'id') => {
  return (req: Request, res: Response, next: NextFunction): void => {
    const paramValue = req.params[paramName];
    
    if (!paramValue) {
      const response: ApiResponse<null> = {
        success: false,
        message: `缺少必需的参数: ${paramName}`,
        data: null,
        timestamp: new Date().toISOString()
      };
      
      res.status(HttpStatus.BAD_REQUEST).json(response);
      return;
    }
    
    // UUID格式验证正则表达式
    const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
    
    if (!uuidRegex.test(paramValue)) {
      const response: ApiResponse<null> = {
        success: false,
        message: `无效的${paramName}格式，必须是有效的UUID`,
        data: null,
        timestamp: new Date().toISOString()
      };
      
      res.status(HttpStatus.BAD_REQUEST).json(response);
      return;
    }
    
    next();
  };
};

/**
 * 查询参数验证中间件
 * 验证分页查询参数的有效性
 * @param req Express请求对象
 * @param res Express响应对象
 * @param next Express下一个中间件函数
 */
export const validateQueryParams = (
  req: Request,
  res: Response,
  next: NextFunction
): void => {
  const { page, limit, sortBy, sortOrder } = req.query;
  const errors: string[] = [];
  
  // 验证页码
  if (page !== undefined) {
    const pageNum = parseInt(page as string, 10);
    if (isNaN(pageNum) || pageNum < 1) {
      errors.push('页码必须是大于0的整数');
    }
  }
  
  // 验证每页数量
  if (limit !== undefined) {
    const limitNum = parseInt(limit as string, 10);
    if (isNaN(limitNum) || limitNum < 1 || limitNum > 100) {
      errors.push('每页数量必须是1-100之间的整数');
    }
  }
  
  // 验证排序字段
  if (sortBy !== undefined) {
    const validSortFields = ['name', 'createdAt', 'updatedAt', 'sortOrder'];
    if (!validSortFields.includes(sortBy as string)) {
      errors.push('排序字段必须是: name, createdAt, updatedAt, sortOrder 之一');
    }
  }
  
  // 验证排序方向
  if (sortOrder !== undefined) {
    const validSortOrders = ['asc', 'desc'];
    if (!validSortOrders.includes(sortOrder as string)) {
      errors.push('排序方向必须是: asc 或 desc');
    }
  }
  
  if (errors.length > 0) {
    const response: ApiResponse<null> = {
      success: false,
      message: '查询参数验证失败',
      data: null,
      errors: errors.map(error => ({ message: error })),
      timestamp: new Date().toISOString()
    };
    
    res.status(HttpStatus.BAD_REQUEST).json(response);
    return;
  }
  
  next();
};

/**
 * 内容类型验证中间件
 * 确保请求的Content-Type为application/json
 * @param req Express请求对象
 * @param res Express响应对象
 * @param next Express下一个中间件函数
 */
export const validateContentType = (
  req: Request,
  res: Response,
  next: NextFunction
): void => {
  // 只对POST、PUT、PATCH请求验证Content-Type
  if (['POST', 'PUT', 'PATCH'].includes(req.method)) {
    const contentType = req.get('Content-Type');
    
    if (!contentType || !contentType.includes('application/json')) {
      const response: ApiResponse<null> = {
        success: false,
        message: '请求头Content-Type必须是application/json',
        data: null,
        timestamp: new Date().toISOString()
      };
      
      res.status(HttpStatus.BAD_REQUEST).json(response);
      return;
    }
  }
  
  next();
};